<template>
  <div class="better-scroll-wrapper" ref="wrapper">
    <component class="better-scroll-content" :is="contentTag">
      <div v-if="pullDown && isOpenPullDown" class="refresh" ref="refresh">
        <div v-show="beforePullDown">
          <span>下拉刷新</span>
        </div>
        <div v-show="!beforePullDown">
          <div v-show="isPullingDown">
            <loading size="17" />
            <span>加载中...</span>
          </div>
          <div v-show="!isPullingDown">
            <span>刷新成功</span>
          </div>
        </div>
      </div>
      <slot></slot>
      <div class="pullUp-tips" v-if="pullUp && isOpenPullUp">
        <div v-if="!isPullUpLoad && !loading" class="before-trigger">
          <span class="pullUp-txt">下拉加载更多</span>
        </div>
        <div v-else class="after-trigger">
          <span class="pullUp-txt"><loading size="17" />加载中...</span>
        </div>
      </div>
    </component>
  </div>
</template>

<script>
import loading from 'components/loading/icon'
import { debounce } from 'common/js/utils'
import BScroll from '@better-scroll/core'
import PullUp from '@better-scroll/pull-up'
import PullDown from '@better-scroll/pull-down'
import ScrollBar from '@better-scroll/scroll-bar'
import MouseWheel from '@better-scroll/mouse-wheel'
BScroll.use(PullDown)
BScroll.use(PullUp)
BScroll.use(ScrollBar)
BScroll.use(MouseWheel)
/**
 * content高度更新后需要重新初始化一次
 */

export default {
  name: 'better-scroll',
  props: {
    /**
     * 1 滚动的时候会派发scroll事件，会截流。
     * 2 滚动的时候实时派发scroll事件，不会截流。
     * 3 除了实时派发scroll事件，在swipe的情况下仍然能实时派发scroll事件
     */
    probeType: {
      type: Number,
      default: 1
    },
    /**
     * 点击列表是否派发click事件
     */
    click: {
      type: Boolean,
      default: true
    },
    /**
     * 是否 X轴 横向滚动
     */
    scrollX: {
      type: Boolean,
      default: false
    },
    /**
     * 是否 Y轴 竖向滚动
     */
    scrollY: {
      type: Boolean,
      default: true
    },
    /**
     * 是否派发scroll滚动事件
     */
    listenScroll: {
      type: Boolean,
      default: false
    },
    /**
     * 显示滚动条
     */
    showScrollBar: {
      type: Boolean,
      default: false
    },

    /**
     * 是否触发顶部下拉事件，用于下拉刷新
     */
    pullDown: {
      type: Boolean,
      default: false
    },
    isOpenPullDown: {
      type: Boolean,
      default: true
    },
    /**
     * 是否触发滚动到底部的事件，用于上拉加载
     */
    pullUp: {
      type: Boolean,
      default: false
    },
    /**
     * 开启/关闭上拉加载
     */
    isOpenPullUp: {
      type: Boolean,
      default: true
    },
    loading: {
      type: Boolean,
      default: false
    },

    /**
     * 是否开启鼠标滚轮
     */
    mouseWheel: {
      type: [Boolean, Object],
      default: () => {
        return {
          speed: 20,
          invert: false,
          easeTime: 300,
          discreteTime: 400,
          throttleTime: 0,
          dampingFactor: 0.1
        }
      }
    },

    /**
     * 是否触发列表滚动开始的事件
     */
    beforeScroll: {
      type: Boolean,
      default: false
    },

    /**
     * 当数据更新后，更新滚动条高度的延时
     */
    refreshDelay: {
      type: Number,
      default: 20
    },
    data: {
      type: Array,
      default () {
        return []
      }
    },
    contentTag: {
      type: String,
      default: 'div'
    }
  },
  data () {
    return {
      scroll: null,
      beforePullDown: false,
      isPullingDown: false,
      isPullUpLoad: false
    }
  },
  mounted () {
    setTimeout(this._initScroll, 20)
  },
  methods: {
    _initScroll () {
      if (!this.$refs.wrapper) return
      this.scroll = new BScroll(this.$refs.wrapper, {
        probeType: this.probeType,
        click: this.click,
        scrollY: this.scrollY,
        scrollX: this.scrollX,
        scrollbar: this.showScrollBar,
        mouseWheel: this.mouseWheel,
        bounceTime: 400,
        pullDownRefresh: this.pullDown, //  下拉刷新
        pullUpLoad: this.pullUp // 上拉加载
      })

      if (this.listenScroll) {
        this.scroll.on('scroll', scroll => {
          this.$emit('scroll', scroll)
        })
      }

      //  下拉刷新事件
      if (this.pullDown) this.scroll.on('pullingDown', this.pullingDown)

      //  上滑加载更多
      if (this.pullUp) this.scroll.on('pullingUp', this.pullingUp)

      if (this.beforeScroll) this.scroll.on('beforeScrollStart', () => this.$emit('beforeScroll'))
      this.$emit('init')
    },

    /* 执行下拉刷新 */
    pullingDown () {
      this.beforePullDown = false
      this.isPullingDown = true
      this.$emit('pullDown')
    },
    /* 结束下拉刷新，才能执行下一次刷新，通过 $refs.scroll.finishPullDown 调用 */
    finishPullDown () {
      this.isPullingDown = false
      setTimeout(() => {
        this.beforePullDown = true
        this.scroll && this.scroll.finishPullDown()
      }, 500)
    },
    autoPullDownRefresh () {
      this.scroll && this.scroll.autoPullDownRefresh()
    },
    openPullDown () {
      this.scroll && this.scroll.openPullDown(true)
    },
    closePullDown () {
      this.scroll && this.scroll.closePullDown()
    },

    /* 上滑加载更多 */
    pullingUp () {
      console.log('触发 上拉加载')
      this.isPullUpLoad = true
      this.$emit('pullUp')
    },
    /* 结束上拉加载 */
    finishPullUp () {
      console.log('完成 上拉加载')
      this.scroll && this.scroll.finishPullUp()
      this.isPullUpLoad = false
    },
    autoPullUpLoad () {
      console.log('自启 上拉加载')
      this.scroll && this.scroll.autoPullUpLoad()
    },
    openPullUp () {
      console.log('开启 上拉加载')
      this.scroll && this.scroll.openPullUp(true)
    },
    closePullUp () {
      console.log('关闭 上拉加载')
      this.scroll && this.scroll.closePullUp()
    },

    refresh: debounce(function () {
      this.scroll && this.scroll.refresh()
    }, this.refreshDelay),
    disable () {
      this.scroll && this.scroll.disable()
    },
    enable () {
      this.scroll && this.scroll.enable()
    },
    scrollTo () {
      this.scroll && this.scroll.scrollTo.apply(this.scroll, arguments)
    },
    scrollToElement () {
      this.scroll && this.scroll.scrollToElement.apply(this.scroll, arguments)
    }
  },
  watch: {
    data () {
      setTimeout(this.refresh, this.refreshDelay)
    },
    isOpenPullDown (newVal, oldVal) {
      if (this.pullDown && newVal !== oldVal) {
        newVal ? this.openPullDown() : this.closePullDown()
      }
    },
    isOpenPullUp (newVal, oldVal) {
      if (this.pullUp && newVal !== oldVal) {
        newVal ? this.openPullUp() : this.closePullUp()
      }
    }
  },
  components: { loading }
}
</script>

<style scoped lang="less">
  @import "~common/style/variable.less";

  .refresh {
    position: absolute;
    width: 100%;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: translateY(-100%) translateZ(0);
    text-align: center;
    color: @color-text-d;
  }

  .pullUp-tips {
    padding: 20px;
    text-align: center;
    color: @color-text-d;
  }

</style>
